package com.muy.redis.view.window.redis.view;

import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ReadAction;
import com.intellij.openapi.fileTypes.PlainTextLanguage;
import com.intellij.openapi.project.Project;
import com.intellij.ui.EditorTextField;
import com.intellij.ui.components.JBLabel;
import com.intellij.ui.components.JBScrollPane;
import com.intellij.ui.components.JBTextArea;
import com.intellij.ui.components.JBTextField;
import com.intellij.ui.table.JBTable;
import com.intellij.ui.table.TableView;
import com.intellij.util.ui.ListTableModel;
import com.muy.redis.common.dialog.ErrorDialog;
import com.muy.redis.common.dialog.MrRedisAddRowDialog;
import com.muy.redis.common.dialog.MrRedisConfirmDialog;
import com.muy.redis.utils.JacksonUtils;
import com.muy.redis.utils.RedisPoolManager;
import com.muy.redis.utils.ThreadPoolManager;
import com.muy.redis.view.component.MrRedisPagingPanel;
import com.muy.redis.view.window.redis.bean.MrRedisDb;
import com.muy.redis.view.window.redis.enums.RedisValueTypeEnum;
import com.muy.redis.view.window.redis.enums.ValueFormatEnum;
import com.muy.redis.view.window.redis.tree.MTTreeCellMrRedisKey;
import com.muy.redis.view.window.redis.view.table.TreeLineObject;
import com.muy.redis.view.window.redis.view.table.TreeLineWrap;
import com.muy.redis.view.window.redis.view.table.bean.RedisHashRow;
import com.muy.redis.view.window.redis.view.table.bean.RedisListRow;
import com.muy.redis.view.window.redis.view.table.bean.RedisSetRow;
import com.muy.redis.view.window.redis.view.table.bean.RedisZSetRow;
import lombok.extern.slf4j.Slf4j;
import org.apache.batik.ext.swing.DoubleDocument;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.jetbrains.annotations.NotNull;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.params.ScanParams;
import redis.clients.jedis.resps.ScanResult;
import redis.clients.jedis.resps.Tuple;

import javax.swing.*;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableColumn;
import java.awt.*;
import java.awt.event.*;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static com.muy.redis.view.window.redis.view.EditorTextFieldManager.createEditorTextField;
import static com.muy.redis.view.window.redis.view.EditorTextFieldManager.formatValue;
import static redis.clients.jedis.params.ScanParams.SCAN_POINTER_START;

/**
 * @Author jiyanghuang
 * @Date 2022/8/4 20:55
 */
@Slf4j
public class MrRedisValueDisplayPanel extends JPanel {

    private static final String REMOVED_VALUE = "_VALUE_REMOVED_BY_AREDIS_";
    private int pageSize = 3;
    private Project project;
    private String key;
    private Value value;
    private Long ttl;
    private RedisValueTypeEnum typeEnum;
    private RedisPoolManager redisPoolManager;
    private MrRedisDb dbInfo;

    private EditorTextField valueTextArea;

    /**
     * value内部预览区 选中的value
     */
    private String selectedValue = "";
    /**
     * value内部预览区 选中的field或者score, 依赖于typeEnum
     */
    private String selectedFieldOrScore = "";
    /**
     * value内部预览区 选中的行
     */
    private int selectedRow = -1;

    /**
     * 一共有多少条数据
     */
    private long total = -1;

    private Map<Integer, String> pageIndexPointerMap;

    private MTTreeCellMrRedisKey mtTreeCellMrRedisKey;

    private TableView tableView = null;

    private MrRedisPagingPanel mrRedisPagingPanel;

    private MrRedisValueDisplayPanel() {
    }

    private MrRedisValueDisplayPanel(LayoutManager layout) {
        super(layout);
        pageIndexPointerMap = new HashMap<>();
        pageIndexPointerMap.put(1, SCAN_POINTER_START);
        this.mrRedisPagingPanel = new MrRedisPagingPanel((s) -> {
            doReload();
        });
        pageSize = this.mrRedisPagingPanel.getPageSize();
    }

    public static MrRedisValueDisplayPanel getInstance() {
        return new MrRedisValueDisplayPanel(new BorderLayout());
    }

    /**
     * 初始化
     *
     * @param project
     * @param parent
     * @param keyTreeDisplayPanel
     * @param key
     * @param redisPoolManager
     * @param dbInfo
     * @param loadingDecorator
     */
    public void init(Project project,
                     String key,
                     RedisPoolManager redisPoolManager,
                     MrRedisDb dbInfo) {
        this.redisPoolManager = redisPoolManager;
        this.dbInfo = dbInfo;
        this.project = project;

        ReadAction.nonBlocking(() -> {
            try (Jedis jedis = redisPoolManager.getJedis(dbInfo.getIndex())) {
                if (jedis == null) {
                    return null;
                }

                Boolean exists = jedis.exists(key);
                if (exists == null || !exists) {
                    ErrorDialog.show("No such key: " + key);
                    return null;
                }

                this.key = key;
                this.ttl = jedis.ttl(key);
                String type = jedis.type(key);


                ScanParams scanParams = new ScanParams();
                scanParams.count(pageSize);
                scanParams.match("*");

                switch (type) {
                    case "string":
                        typeEnum = RedisValueTypeEnum.String;
                        String stringValue = jedis.get(key);
                        value = new Value(stringValue);
                        break;

                    case "list":
                        typeEnum = RedisValueTypeEnum.List;
                        int start = (this.mrRedisPagingPanel.getPageIndex() - 1) * pageSize;
                        total = jedis.llen(key);
                        mrRedisPagingPanel.updateTotal(total);
                        List<String> listValue = jedis.lrange(key, start, start + pageSize - 1);
                        mrRedisPagingPanel.updateCurrentPageCount(listValue.size());
                        value = new Value(listValue);
                        break;

                    case "set":
                        typeEnum = RedisValueTypeEnum.Set;
                        total = jedis.scard(key);
                        mrRedisPagingPanel.updateTotal(total);
                        String setPointer = pageIndexPointerMap.get(this.mrRedisPagingPanel.getPageIndex());
                        ScanResult<String> sscanResult = jedis.sscan(key, setPointer, scanParams);
                        mrRedisPagingPanel.updateCurrentPageCount(sscanResult.getResult().size());
                        pageIndexPointerMap.put(this.mrRedisPagingPanel.getPageIndex() + 1, sscanResult.getCursor());
                        value = new Value(sscanResult.getResult());
                        break;

                    case "zset":
                        typeEnum = RedisValueTypeEnum.Zset;
                        total = jedis.zcard(key);
                        mrRedisPagingPanel.updateTotal(total);
                        String zsetPointer = pageIndexPointerMap.get(this.mrRedisPagingPanel.getPageIndex());
                        ScanResult<Tuple> zscanResult = jedis.zscan(key, zsetPointer, scanParams);
                        mrRedisPagingPanel.updateCurrentPageCount(zscanResult.getResult().size());
                        pageIndexPointerMap.put(this.mrRedisPagingPanel.getPageIndex() + 1, zscanResult.getCursor());
                        value = new Value(zscanResult.getResult());
                        break;

                    case "hash":
                        typeEnum = RedisValueTypeEnum.Hash;
                        total = jedis.hlen(key);
                        mrRedisPagingPanel.updateTotal(total);
                        String hashPointer = pageIndexPointerMap.get(this.mrRedisPagingPanel.getPageIndex());
                        // 分页不一定生效，当它是压缩列表时，会返回全部数据，只有当它是字典时会生效
                        ScanResult<Map.Entry<String, String>> hscanResult = jedis.hscan(key, hashPointer, scanParams);
                        mrRedisPagingPanel.updateCurrentPageCount(hscanResult.getResult().size());
                        pageIndexPointerMap.put(this.mrRedisPagingPanel.getPageIndex() + 1, hscanResult.getCursor());
                        value = new Value(hscanResult.getResult());
                        break;

                    default:
                        return null;
                }

                ApplicationManager.getApplication().invokeLater(this::initWithValue);
            } finally {
//                loadingDecorator.stopLoading();
            }
            return null;
        }).submit(ThreadPoolManager.getExecutor());

    }

    private void initWithValue() {
        // key 不存在
        if (value == null) {
            return;
        }

        this.removeAll();

        // 初始化value预览工具栏区
        initValuePreviewToolbarPanel();

        // 初始化value预览区
        initValuePreviewPanelV3();
    }

    /**
     * 初始化value预览工具栏区
     */
    private void initValuePreviewToolbarPanel() {
        JBTextField keyTextField = new JBTextField(key);
        keyTextField.setPreferredSize(new Dimension(200, 28));
        keyTextField.setToolTipText(keyTextField.getText());
        keyTextField.addKeyListener(new KeyListener() {
            @Override
            public void keyTyped(KeyEvent e) {
            }

            @Override
            public void keyPressed(KeyEvent e) {
            }

            @Override
            public void keyReleased(KeyEvent e) {
                keyTextField.setToolTipText(keyTextField.getText());
            }
        });

        JButton renameButton = createRenameButton(keyTextField);

//        JButton reloadButton = createReloadValueButton();

//        JButton deleteButton = createDeleteButton();

        JBTextField ttlTextField = new JBTextField();
        ttlTextField.setDocument(new DoubleDocument());
        ttlTextField.setPreferredSize(new Dimension(70, 27));
        ttlTextField.setText(ttl.toString());

        JButton ttlButton = createTTLButton(ttlTextField);

        /**
         * value预览工具栏区
         */
        JPanel valuePreviewToolbarPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
        valuePreviewToolbarPanel.add(new JLabel(typeEnum.name() + ":"));
        valuePreviewToolbarPanel.add(keyTextField);
        valuePreviewToolbarPanel.add(renameButton);
//        valuePreviewToolbarPanel.add(reloadButton);
//        valuePreviewToolbarPanel.add(deleteButton);
        valuePreviewToolbarPanel.add(new JLabel("TTL:"));
        valuePreviewToolbarPanel.add(ttlTextField);
        valuePreviewToolbarPanel.add(ttlButton);

        this.add(valuePreviewToolbarPanel, BorderLayout.NORTH);
    }

    @NotNull
    private JButton createTTLButton(JBTextField ttlTextField) {
        JButton ttlButton = new JButton("Set new TTL");
        ttlButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                String text = ttlTextField.getText();
                new MrRedisConfirmDialog("Are you sure you want to set TTL to %s?", "Confirm", project, (form) -> {
                    try (Jedis jedis = redisPoolManager.getJedis(dbInfo.getIndex())) {
                        if (jedis == null) {
                            return Pair.of(false, "invalid jedis");
                        }

                        long newTtl = Long.parseLong(text);
                        if (newTtl < 0) {
                            newTtl = -1;
                        }
                        jedis.expire(key, newTtl);
                        ttl = newTtl;
                        ttlTextField.setText(ttl.toString());
                    } catch (NumberFormatException exception) {
                        ErrorDialog.show("Wrong TTL format for input: " + text);
                        return Pair.of(false, "invalid jedis");
                    }
                    return Pair.of(true, null);
                }).ofDialogShow();
            }
        });
        return ttlButton;
    }

    @NotNull
    private JButton createDeleteButton() {
        JButton deleteButton = new JButton("Delete");
        deleteButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                new MrRedisConfirmDialog("Are you sure you want to delete this key?", "Confirm", project, (form) -> {
                    try (Jedis jedis = redisPoolManager.getJedis(dbInfo.getIndex())) {
                        if (null == jedis) {
                            return Pair.of(false, null);
                        }
                    }
                    return Pair.of(true, null);
                }).ofDialogShow();
            }
        });
        return deleteButton;
    }

    private void initValuePreviewPanelV3() {
        DefaultTableModel tableModel = null;
        ListTableModel listTableModel = null;
        JPanel jPanelCenter = null;
        switch (typeEnum) {
            case String:
                tableModel = null;
                jPanelCenter = stringValuePreview();
                break;

            case List:
                List<String> listValue = value.getListValue();
                List<RedisListRow> redisListRows = RedisListRow.genTableData(listValue, typeEnum, calPageIndex(), this::saveNewValueCallBack);
                listTableModel = TreeLineWrap.buildJsonTable(RedisListRow.class, redisListRows, project);
                jPanelCenter = tablePreview(listTableModel);
                break;

            case Set:
                List<String> setValue = value.getSetValue();
                List<RedisSetRow> redisSetRows = RedisSetRow.genTableData(setValue, typeEnum, this::saveNewValueCallBack);
                listTableModel = TreeLineWrap.buildJsonTable(RedisSetRow.class, redisSetRows, project);
                jPanelCenter = tablePreview(listTableModel);
                break;

            case Zset:
                List<Tuple> zsetValue = value.getZsetValue();
                List<RedisZSetRow> redisZSetRows = RedisZSetRow.genTableData(zsetValue, typeEnum, this::saveNewValueCallBack);
                listTableModel = TreeLineWrap.buildJsonTable(RedisZSetRow.class, redisZSetRows, project);
                jPanelCenter = tablePreview(listTableModel);
                break;

            case Hash:
                List<Map.Entry<String, String>> hashValue = value.getHashValue();
                List<RedisHashRow> redisHashRows = RedisHashRow.genTableData(hashValue, typeEnum, this::saveNewValueCallBack);
                listTableModel = TreeLineWrap.buildJsonTable(RedisHashRow.class, redisHashRows, project);
                jPanelCenter = tablePreview(listTableModel);
                break;

            default:
                return;
        }
        this.add(jPanelCenter, BorderLayout.CENTER);
        mrRedisPagingPanel.updatePageLabel();
    }

    private JPanel tablePreview(ListTableModel listTableModel) {
        JBTable valueTable = TreeLineWrap.tableView(listTableModel);
        tableView = (TableView) valueTable;
        JPanel innerPreviewPanel = new JPanel(new BorderLayout());
        JButton addRowButton = createAddRowButton();
        JButton deleteRowButton = createDeleteRowButton();

        JPanel rowButtonPanel = new JPanel(new BorderLayout());
        rowButtonPanel.add(addRowButton, BorderLayout.NORTH);
        rowButtonPanel.add(deleteRowButton, BorderLayout.SOUTH);

        JPanel valueTableButtonPanel = new JPanel(new BorderLayout());
        valueTableButtonPanel.add(rowButtonPanel, BorderLayout.NORTH);
        valueTableButtonPanel.add(mrRedisPagingPanel, BorderLayout.SOUTH);

        JBScrollPane valueTableScrollPane = new JBScrollPane(valueTable);
        /**
         * value内部预览区
         */
        JPanel valueInnerPreviewPanel = new JPanel(new BorderLayout());
        valueInnerPreviewPanel.add(valueTableScrollPane, BorderLayout.CENTER);
        valueInnerPreviewPanel.add(valueTableButtonPanel, BorderLayout.AFTER_LINE_ENDS);

        innerPreviewPanel.add(valueInnerPreviewPanel, BorderLayout.CENTER);
        return innerPreviewPanel;
    }

    private JPanel stringValuePreview() {
        JPanel valuePreviewAndFunctionPanel = new JPanel(new BorderLayout());
        JBTextArea fieldTextArea = new JBTextArea();
        fieldTextArea.setLineWrap(true);
        fieldTextArea.setAutoscrolls(true);

        valueTextArea = createEditorTextField(project, PlainTextLanguage.INSTANCE, "");

        JPanel viewAsAndSavePanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
        viewAsAndSavePanel.add(new JLabel("View as:"));
        JComboBox<ValueFormatEnum> valueFormatComboBox = new JComboBox<>(ValueFormatEnum.values());
        // View as 功能
        valueFormatComboBox.addItemListener(new ItemListener() {
            @Override
            public void itemStateChanged(ItemEvent e) {
                if (ItemEvent.SELECTED == e.getStateChange()) {
                    ValueFormatEnum formatEnum = (ValueFormatEnum) e.getItem();
                    valueTextArea = formatValue(project, valuePreviewAndFunctionPanel, formatEnum, valueTextArea);
                }
            }
        });

        JButton saveValueButton = createSaveValueButton(fieldTextArea);
        viewAsAndSavePanel.add(valueFormatComboBox);
        viewAsAndSavePanel.add(saveValueButton);

        JBLabel valueSizeLabel = new JBLabel();
        updateValueSize(valueSizeLabel);
        /**
         * value功能区
         */
        JPanel valueFunctionPanel = new JPanel(new BorderLayout());
        valueFunctionPanel.add(valueSizeLabel, BorderLayout.WEST);
        valueFunctionPanel.add(viewAsAndSavePanel, BorderLayout.AFTER_LINE_ENDS);

        /**
         * value视图区
         */

        // value size/view as and value preview
        valuePreviewAndFunctionPanel.add(valueFunctionPanel, BorderLayout.NORTH);
        valuePreviewAndFunctionPanel.add(valueTextArea, BorderLayout.CENTER);

        JPanel innerPreviewPanel = new JPanel(new BorderLayout());

        selectedValue = value.getStringValue();
        if (JacksonUtils.jsonStr(selectedValue)) {
            valueFormatComboBox.setSelectedItem(ValueFormatEnum.JSON);
        }
        valueTextArea.setText(getSelectedValue());
        updateValueSize(valueSizeLabel);

        JPanel valuePreviewPanel = new JPanel(new BorderLayout());
        valuePreviewPanel.add(innerPreviewPanel, BorderLayout.NORTH);
        valuePreviewPanel.add(valuePreviewAndFunctionPanel, BorderLayout.CENTER);

        return valuePreviewPanel;
    }

    @NotNull
    private JBTable createValueTable(DefaultTableModel tableModel, int valueColumnIndex, int fieldOrScoreColumnIndex, JBTextArea fieldTextArea, JBLabel valueSizeLabel) {
        JBTable valueTable = new JBTable(tableModel) {
            @Override
            public boolean isCellEditable(int row, int column) {
                return false;
            }
        };

        // 只能选中一行
        valueTable.setRowSelectionAllowed(true);
        valueTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);

        // 设置第一列的最大宽度
        TableColumn column = valueTable.getColumnModel().getColumn(0);
        column.setMaxWidth(150);

        DefaultTableCellRenderer tableCellRenderer = new DefaultTableCellRenderer();
        tableCellRenderer.setHorizontalAlignment(SwingConstants.CENTER);
        // 数据局中
        valueTable.setDefaultRenderer(Object.class, tableCellRenderer);
        // 表头居中
        valueTable.getTableHeader().setDefaultRenderer(tableCellRenderer);

        // value视图区展示选中的行
        valueTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
            @Override
            public void valueChanged(ListSelectionEvent e) {
                if (!e.getValueIsAdjusting()) {
                    int selectedRow = valueTable.getSelectedRow();
                    updateSelected(selectedRow,
                            tableModel.getValueAt(selectedRow, valueColumnIndex).toString(),
                            tableModel.getValueAt(selectedRow, fieldOrScoreColumnIndex).toString());
                    fieldTextArea.setText(getSelectedFieldOrScore());
                    valueTextArea.setText(getSelectedValue());
                    valueTextArea.updateUI();
                    updateValueSize(valueSizeLabel);
                }
            }
        });

        return valueTable;
    }

    @NotNull
    private JButton createDeleteRowButton() {
        JButton deleteRowButton = new JButton("Delete row");
        deleteRowButton.setAlignmentX(Component.CENTER_ALIGNMENT);
        deleteRowButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                int selectRowIndex = tableView.getSelectedRow();
                if (selectRowIndex < 0) {
                    ErrorDialog.show("Please select a row!");
                    return;
                }
                new MrRedisConfirmDialog("Do you really want to remove this row?", "Confirm", project, (form) -> {
                    try (Jedis jedis = redisPoolManager.getJedis(dbInfo.getIndex())) {
                        if (jedis == null) {
                            return Pair.of(false, null);
                        }
                        if (!jedis.exists(key)) {
                            ErrorDialog.show(String.format("No such key: %s", key));
                        } else {
                            switch (typeEnum) {
                                case List:
                                    jedis.lset(key, getSelectedIndex(), REMOVED_VALUE);
                                    jedis.lrem(key, 0, REMOVED_VALUE);
                                    break;

                                case Set:
                                    jedis.srem(key, getSelectedValue());
                                    break;

                                case Zset:
                                    jedis.zrem(key, getSelectedValue());
                                    break;

                                case Hash:
                                    jedis.hdel(key, getSelectedFieldOrScore());
                                    break;

                                default:
                            }
                            if (-1 != selectRowIndex) {
                                ListTableModel listTableModel = (ListTableModel) tableView.getModel();
                                listTableModel.removeRow(selectRowIndex);
                                ApplicationManager.getApplication().invokeLater(() -> {
                                    tableView.updateUI();
                                });
                            }
                        }
                    } catch (Exception exception) {
                        log.error("Failed to save value", exception);
                    }
                    return Pair.of(true, null);
                }).ofDialogShow();
            }
        });
        return deleteRowButton;
    }

    @NotNull
    private JButton createAddRowButton() {
        JButton addRowButton = new JButton("Add row");
        addRowButton.setAlignmentX(Component.CENTER_ALIGNMENT);
        addRowButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                new MrRedisAddRowDialog(project, typeEnum, (form) -> {
                    try (Jedis jedis = redisPoolManager.getJedis(dbInfo.getIndex())) {
                        if (jedis == null) {
                            return Pair.of(false, null);
                        }
                        if (!jedis.exists(key)) {
                            ErrorDialog.show(String.format("No such key: %s", key));
//                            addRowDialog.close(OK_EXIT_CODE);
                            return Pair.of(false, null);
                        } else {
                            TreeLineWrap treeLineWrap = null;
                            switch (typeEnum) {
                                case List:
                                    jedis.lpush(key, form.getValue());
                                    RedisListRow redisListRow = new RedisListRow();
                                    redisListRow.setRow(tableView.getRowCount());
                                    redisListRow.setValue(form.getValue());
                                    treeLineWrap = TreeLineWrap.createRowValue(RedisListRow.class, redisListRow, project);
                                    break;

                                case Set:
                                    jedis.sadd(key, form.getValue());
                                    RedisSetRow redisSetRow = new RedisSetRow();
                                    redisSetRow.setRow(tableView.getRowCount());
                                    redisSetRow.setValue(form.getValue());
                                    treeLineWrap = TreeLineWrap.createRowValue(RedisSetRow.class, redisSetRow, project);
                                    break;

                                case Zset:
                                    jedis.zadd(key, Double.parseDouble(form.getScoreOrField()), form.getValue());
                                    RedisZSetRow redisZSetRow = new RedisZSetRow();
                                    redisZSetRow.setRow(tableView.getRowCount());
                                    redisZSetRow.setScore(Double.parseDouble(form.getScoreOrField()));
                                    redisZSetRow.setValue(form.getValue());
                                    treeLineWrap = TreeLineWrap.createRowValue(RedisZSetRow.class, redisZSetRow, project);
                                    break;

                                case Hash:
                                    jedis.hset(key, form.getScoreOrField(), form.getValue());
                                    RedisHashRow redisHashRow = new RedisHashRow();
                                    redisHashRow.setRow(tableView.getRowCount());
                                    redisHashRow.setField(form.getScoreOrField());
                                    redisHashRow.setValue(form.getValue());
                                    treeLineWrap = TreeLineWrap.createRowValue(RedisHashRow.class, redisHashRow, project);
                                    break;

                                default:
                            }
                            if (null != treeLineWrap) {
                                ListTableModel listTableModel = (ListTableModel) tableView.getModel();
                                listTableModel.addRow(treeLineWrap);
                                ApplicationManager.getApplication().invokeLater(() -> {
                                    tableView.updateUI();
                                });
                            }
//                            doReload();
                        }
                        return Pair.of(true, null);
                    } catch (Exception exception) {
                        log.error("Failed to save value", exception);
                        return Pair.of(true, null);
                    }
                }).ofDialogShow();
            }
        });
        return addRowButton;
    }

    @NotNull
    private JButton createSaveValueButton(JBTextArea fieldTextArea) {
        JButton saveValueButton = new JButton("Save");
        saveValueButton.setEnabled(true);
        saveValueButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                if (selectedRow == -1 && typeEnum != RedisValueTypeEnum.String) {
                    return;
                }

                String newField = fieldTextArea.getText();
                if (typeEnum == RedisValueTypeEnum.Hash) {
                    if (StringUtils.isEmpty(newField)) {
                        ErrorDialog.show("Please enter a valid Field!");
                        return;
                    }
                }

                if (typeEnum == RedisValueTypeEnum.Hash) {
                    if (StringUtils.isEmpty(newField)) {
                        ErrorDialog.show("Please enter a valid Score!");
                        return;
                    }
                }

                String newValue = valueTextArea.getText();
                if (StringUtils.isEmpty(newValue)) {
                    ErrorDialog.show("Please enter a valid Value!");
                    return;
                }
                new MrRedisConfirmDialog("Do you really want to save this?", "Confirm", project, (form) -> {
                    saveNewValue(newField, newValue);
                    return Pair.of(true, null);
                }).ofDialogShow();
            }
        });
        return saveValueButton;
    }

    private void saveNewValue(String newFieldOrScore, String newValue) {
        switch (typeEnum) {
            case String:
                try (Jedis jedis = redisPoolManager.getJedis(dbInfo.getIndex())) {
                    if (jedis == null) {
                        return;
                    }
                    jedis.set(key, newValue);
                }
                break;

            case List:
                try (Jedis jedis = redisPoolManager.getJedis(dbInfo.getIndex())) {
                    if (jedis == null) {
                        return;
                    }
                    int selectedIndex = getSelectedIndex();
                    if (selectedIndex >= 0) {
                        jedis.lset(key, selectedIndex, newValue);
                    }
                }
                break;

            case Set:
                try (Jedis jedis = redisPoolManager.getJedis(dbInfo.getIndex())) {
                    if (jedis == null) {
                        return;
                    }
                    if (selectedRow >= 0 && !getSelectedValue().equals(newValue)) {
                        jedis.srem(key, getSelectedValue());
                        jedis.sadd(key, newValue);
                    }
                }
                break;

            case Zset:
                try (Jedis jedis = redisPoolManager.getJedis(dbInfo.getIndex())) {
                    if (jedis == null) {
                        return;
                    }
                    if (selectedRow >= 0 && StringUtils.isNotEmpty(newFieldOrScore)) {
                        jedis.zrem(key, getSelectedValue());
                        jedis.zadd(key, Double.parseDouble(newFieldOrScore), newValue);
                    }
                }
                break;

            case Hash:
                try (Jedis jedis = redisPoolManager.getJedis(dbInfo.getIndex())) {
                    if (jedis == null) {
                        return;
                    }
                    if (selectedRow >= 0 && StringUtils.isNotEmpty(getSelectedFieldOrScore())) {
                        jedis.hdel(key, getSelectedFieldOrScore());
                        jedis.hset(key, newFieldOrScore, newValue);
                    }
                }
                break;

            default:
                return;
        }

        // 重新加载
        doReload();

    }

    public void saveNewValueCallBack(TreeLineObject old, TreeLineObject update) {
        saveNewValue(old, update);
    }

    private void saveNewValue(TreeLineObject old, TreeLineObject update) {
        switch (typeEnum) {
            case String:
                try (Jedis jedis = redisPoolManager.getJedis(dbInfo.getIndex())) {
                    if (jedis == null) {
                        return;
                    }
                    // 字符串通过Save操作来更新
                    jedis.set(key, "");
                }
                break;

            case List:
                try (Jedis jedis = redisPoolManager.getJedis(dbInfo.getIndex())) {
                    if (jedis == null) {
                        return;
                    }
                    RedisListRow redisListRow = (RedisListRow) update;
                    jedis.lset(key, redisListRow.getSelectIndex(), redisListRow.getValue());
                }
                break;

            case Set:
                try (Jedis jedis = redisPoolManager.getJedis(dbInfo.getIndex())) {
                    if (jedis == null) {
                        return;
                    }
                    RedisSetRow redisSetRowOld = (RedisSetRow) old;
                    RedisSetRow redisSetRowUpdate = (RedisSetRow) update;
                    jedis.srem(key, redisSetRowOld.getValue());
                    jedis.sadd(key, redisSetRowUpdate.getValue());
                }
                break;

            case Zset:
                try (Jedis jedis = redisPoolManager.getJedis(dbInfo.getIndex())) {
                    if (jedis == null) {
                        return;
                    }
                    RedisZSetRow redisZSetRowOld = (RedisZSetRow) old;
                    RedisZSetRow redisZSetRowUpdate = (RedisZSetRow) update;
                    jedis.zrem(key, redisZSetRowOld.getValue());
                    jedis.zadd(key, redisZSetRowUpdate.getScore(), redisZSetRowUpdate.getValue());
                }
                break;

            case Hash:
                try (Jedis jedis = redisPoolManager.getJedis(dbInfo.getIndex())) {
                    if (jedis == null) {
                        return;
                    }
                    RedisHashRow redisHashRowOld = (RedisHashRow) old;
                    RedisHashRow redisHashRowUpdate = (RedisHashRow) update;
                    jedis.hdel(key, redisHashRowOld.getField());
                    jedis.hset(key, redisHashRowUpdate.getField(), redisHashRowUpdate.getValue());
                }
                break;

            default:
                return;
        }
        // 重新加载
        doReload();

    }

    @NotNull
    private JButton createRenameButton(JBTextField keyTextField) {
        JButton renameButton = new JButton("Rename key");
        renameButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                final String newKey = keyTextField.getText();
                new MrRedisConfirmDialog(String.format("Do you want to rename \"%s\" to \"%s\"?", key, newKey), "Confirm", project, (form) -> {
                    try (Jedis jedis = redisPoolManager.getJedis(dbInfo.getIndex())) {
                        if (jedis == null) {
                            return Pair.of(false, null);
                        }
                        final Long renamenx = jedis.renamenx(key, newKey);
                        if (renamenx == 0) {
                            ErrorDialog.show(String.format("\"%s\" already exists!", newKey));
                        } else {
                            key = newKey;
                            mtTreeCellMrRedisKey.setRedisKey(key);
                        }
                    } catch (Exception exception) {
                        ErrorDialog.show(exception.getMessage());
                    }
                    return Pair.of(true, null);
                }).ofDialogShow();
            }
        });
        return renameButton;
    }

    public void doReload() {
        init(project, key, redisPoolManager, dbInfo);
        updateSelected(-1, "", "");
        this.updateUI();
    }

    /**
     * 更新value size标签
     *
     * @param valueSizeLabel
     */
    private void updateValueSize(JLabel valueSizeLabel) {
        valueSizeLabel.setText("Value size: " + getSelectedValue().getBytes(StandardCharsets.UTF_8).length + "bytes");
    }

    private String getSelectedFieldOrScore() {
        return this.selectedFieldOrScore;
    }

    private String getSelectedValue() {
        return this.selectedValue;
    }

    private void updateSelected(int selectedRow, String selectedValue, String selectedFieldOrScore) {
        this.selectedRow = selectedRow;
        this.selectedValue = selectedValue;
        this.selectedFieldOrScore = selectedFieldOrScore;
    }

    private int getSelectedIndex() {
        return (this.mrRedisPagingPanel.getPageIndex() - 1) * pageSize + selectedRow;
    }

    private int calPageIndex() {
        return (this.mrRedisPagingPanel.getPageIndex() - 1) * pageSize;
    }

    public String getKey() {
        return this.key;
    }


    public void setMtTreeCellMrRedisKey(MTTreeCellMrRedisKey mtTreeCellMrRedisKey) {
        this.mtTreeCellMrRedisKey = mtTreeCellMrRedisKey;
    }

    /**
     * 计算页数
     *
     * @return
     */
    private long getPageCount() {
        long result = total / pageSize;
        long mod = total % pageSize;
        return mod > 0 ? result + 1 : result;
    }

    private class Value {
        private final Object valueData;

        public Value(Object valueData) {
            this.valueData = valueData;
        }

        public String getStringValue() {
            return valueData.toString();
        }

        public List<String> getListValue() {
            return (List<String>) valueData;
        }

        public List<String> getSetValue() {
            return getListValue();
        }

        public List<Tuple> getZsetValue() {
            return (List<Tuple>) valueData;
        }

        public List<Map.Entry<String, String>> getHashValue() {
            return (List<Map.Entry<String, String>>) valueData;
        }
    }
}
